//! Flight SQL协议定义和工具函数

use serde::{Deserialize, Serialize};

/// Flight SQL命令类型
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum FlightSqlCommand {
    /// SQL查询
    Query { sql: String },
    /// 获取表列表
    GetTables { catalog: Option<String>, schema: Option<String> },
    /// 获取Schema
    GetSchema { catalog: Option<String>, schema: Option<String>, table: String },
    /// 获取列信息
    GetColumns { catalog: Option<String>, schema: Option<String>, table: String },
    /// 获取主键
    GetPrimaryKeys { catalog: Option<String>, schema: Option<String>, table: String },
    /// 获取外键
    GetForeignKeys { catalog: Option<String>, schema: Option<String>, table: String },
}

/// Flight SQL响应类型
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum FlightSqlResponse {
    /// 查询结果
    QueryResult { rows: u64, columns: u32 },
    /// 表列表
    Tables { tables: Vec<TableInfo> },
    /// Schema信息
    Schema { schema: SchemaInfo },
    /// 列信息
    Columns { columns: Vec<ColumnInfo> },
    /// 错误信息
    Error { message: String },
}

/// 表信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TableInfo {
    /// 表名
    pub name: String,
    /// 表类型
    pub table_type: String,
    /// 注释
    pub comment: Option<String>,
}

/// Schema信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SchemaInfo {
    /// Schema名称
    pub name: String,
    /// 表列表
    pub tables: Vec<TableInfo>,
}

/// 列信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ColumnInfo {
    /// 列名
    pub name: String,
    /// 数据类型
    pub data_type: String,
    /// 是否可为空
    pub nullable: bool,
    /// 默认值
    pub default_value: Option<String>,
    /// 注释
    pub comment: Option<String>,
}

/// Flight SQL工具函数
pub struct FlightSqlUtils;

impl FlightSqlUtils {
    /// 编码Flight SQL命令
    pub fn encode_command(command: &FlightSqlCommand) -> Result<Vec<u8>, serde_json::Error> {
        serde_json::to_vec(command)
    }
    
    /// 解码Flight SQL命令
    pub fn decode_command(data: &[u8]) -> Result<FlightSqlCommand, serde_json::Error> {
        serde_json::from_slice(data)
    }
    
    /// 编码Flight SQL响应
    pub fn encode_response(response: &FlightSqlResponse) -> Result<Vec<u8>, serde_json::Error> {
        serde_json::to_vec(response)
    }
    
    /// 解码Flight SQL响应
    pub fn decode_response(data: &[u8]) -> Result<FlightSqlResponse, serde_json::Error> {
        serde_json::from_slice(data)
    }
    
    /// 创建SQL查询命令
    pub fn create_query_command(sql: &str) -> FlightSqlCommand {
        FlightSqlCommand::Query {
            sql: sql.to_string(),
        }
    }
    
    /// 创建获取表列表命令
    pub fn create_get_tables_command(
        catalog: Option<String>,
        schema: Option<String>,
    ) -> FlightSqlCommand {
        FlightSqlCommand::GetTables { catalog, schema }
    }
    
    /// 创建获取Schema命令
    pub fn create_get_schema_command(
        catalog: Option<String>,
        schema: Option<String>,
        table: String,
    ) -> FlightSqlCommand {
        FlightSqlCommand::GetSchema { catalog, schema, table }
    }
    
    /// 验证SQL语句
    pub fn validate_sql(sql: &str) -> bool {
        // 基本的SQL验证
        if sql.trim().is_empty() {
            return false;
        }
        
        let sql_upper = sql.trim().to_uppercase();
        
        // 检查是否是支持的SQL语句
        sql_upper.starts_with("SELECT") ||
        sql_upper.starts_with("SHOW") ||
        sql_upper.starts_with("DESCRIBE") ||
        sql_upper.starts_with("EXPLAIN")
    }
    
    /// 清理SQL语句
    pub fn sanitize_sql(sql: &str) -> String {
        // 移除多余的空白字符
        sql.trim()
            .lines()
            .map(|line| line.trim())
            .filter(|line| !line.is_empty())
            .collect::<Vec<_>>()
            .join(" ")
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_flight_sql_command_encoding() {
        let command = FlightSqlCommand::Query {
            sql: "SELECT * FROM users".to_string(),
        };
        
        let encoded = FlightSqlUtils::encode_command(&command).unwrap();
        let decoded = FlightSqlUtils::decode_command(&encoded).unwrap();
        
        match decoded {
            FlightSqlCommand::Query { sql } => {
                assert_eq!(sql, "SELECT * FROM users");
            },
            _ => panic!("解码失败"),
        }
    }
    
    #[test]
    fn test_flight_sql_response_encoding() {
        let response = FlightSqlResponse::QueryResult {
            rows: 100,
            columns: 5,
        };
        
        let encoded = FlightSqlUtils::encode_response(&response).unwrap();
        let decoded = FlightSqlUtils::decode_response(&encoded).unwrap();
        
        match decoded {
            FlightSqlResponse::QueryResult { rows, columns } => {
                assert_eq!(rows, 100);
                assert_eq!(columns, 5);
            },
            _ => panic!("解码失败"),
        }
    }
    
    #[test]
    fn test_sql_validation() {
        assert!(FlightSqlUtils::validate_sql("SELECT * FROM users"));
        assert!(FlightSqlUtils::validate_sql("SHOW TABLES"));
        assert!(FlightSqlUtils::validate_sql("DESCRIBE users"));
        assert!(FlightSqlUtils::validate_sql("EXPLAIN SELECT * FROM users"));
        
        assert!(!FlightSqlUtils::validate_sql(""));
        assert!(!FlightSqlUtils::validate_sql("   "));
        assert!(!FlightSqlUtils::validate_sql("INSERT INTO users VALUES (1, 'test')"));
        assert!(!FlightSqlUtils::validate_sql("DELETE FROM users"));
    }
    
    #[test]
    fn test_sql_sanitization() {
        let sql = "  SELECT   *  \n  FROM   users  \n  WHERE  id = 1  ";
        let sanitized = FlightSqlUtils::sanitize_sql(sql);
        assert_eq!(sanitized, "SELECT * FROM users WHERE id = 1");
    }
    
    #[test]
    fn test_command_creation() {
        let query_cmd = FlightSqlUtils::create_query_command("SELECT 1");
        match query_cmd {
            FlightSqlCommand::Query { sql } => assert_eq!(sql, "SELECT 1"),
            _ => panic!("命令类型错误"),
        }
        
        let tables_cmd = FlightSqlUtils::create_get_tables_command(
            Some("catalog".to_string()),
            Some("schema".to_string()),
        );
        match tables_cmd {
            FlightSqlCommand::GetTables { catalog, schema } => {
                assert_eq!(catalog, Some("catalog".to_string()));
                assert_eq!(schema, Some("schema".to_string()));
            },
            _ => panic!("命令类型错误"),
        }
    }
}
